package manager

import (
	"encoding/json"
	"errors"
	"strconv"
	"time"

	"gorm.io/gorm"

	"gitcode.com/G-YT/baoyou/server/global"
	"gitcode.com/G-YT/baoyou/server/model/common/response"
	"gitcode.com/G-YT/baoyou/server/model/manager"
	managerReq "gitcode.com/G-YT/baoyou/server/model/manager/request"
	managerRes "gitcode.com/G-YT/baoyou/server/model/manager/response"
	"gitcode.com/G-YT/baoyou/server/model/system"
	"gitcode.com/G-YT/baoyou/server/utils"
	"gitcode.com/G-YT/baoyou/server/utils/sms"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

type HealthManagerApi struct {
}

// Register 注册
// @Tags HealthManager
// @Summary 注册
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body manager.HealthManager true "RegisterRequest"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /base/register [post]
func (healthManagerApi *HealthManagerApi) Register(c *gin.Context) {
	var registerInfo managerReq.RegisterRequest
	err := c.ShouldBindJSON(&registerInfo)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	verify := utils.Rules{
		"Phone":            {utils.NotEmpty()},
		"Password":         {utils.NotEmpty()},
		"Name":             {utils.NotEmpty()},
		"ServiceStationID": {utils.NotEmpty()},
	}
	if err := utils.Verify(registerInfo, verify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err := HealthManagerService.CreateHealthManager(registerInfo); err != nil {
		global.GVA_LOG.Error(err.Error(), zap.Error(err))
		response.FailWithMessage(err.Error(), c)
	} else {
		response.OkWithMessage("提交注册申请成功", c)
	}
}

// PasswordLogin 密码登录
// @Tags HealthManager
// @Summary 密码登录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body manager.FdHealthManager true "密码登录"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"登陆成功"}"
// @Router /healthManager/passwordLogin [post]
func (healthManagerApi *HealthManagerApi) PasswordLogin(c *gin.Context) {
	var mp managerReq.PasswordLoginRequest
	err := c.ShouldBindJSON(&mp)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(mp, utils.PasswordLoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	info := manager.HealthManager{
		Phone:    mp.Phone,
		Password: mp.Password,
	}
	managerInfo, loginErr := HealthManagerService.Login(&info)
	if loginErr != nil {
		response.FailWithMessage(loginErr.Error(), c)
		return
	}
	healthManagerApi.TokenNextB1(c, *managerInfo)
}

// CodeLogin 验证码登录
// @Tags HealthManager
// @Summary 验证码登录
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body manager.FdHealthManager true "验证码登录"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"登录成功"}"
// @Router /healthManager/codeLogin [post]
func (healthManagerApi *HealthManagerApi) CodeLogin(c *gin.Context) {
	var uc managerReq.CodeLoginRequest
	err := c.ShouldBindJSON(&uc)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(uc, utils.CodeLoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if smsErr := sms.CheckSMSCode(uc.Phone, uc.Code); smsErr != nil {
		response.FailWithMessage("验证码有误,请核实!", c)
		return
	}
	managerInfo, loginErr := HealthManagerService.FindManagerByWhere(map[string]interface{}{"phone": uc.Phone}, "*")
	if errors.Is(loginErr, gorm.ErrRecordNotFound) {
		response.FailWithMessage("请先注册后登录", c)
		return
	}
	switch managerInfo.RegisterStatus {
	case 1:
		healthManagerApi.TokenNextB1(c, *managerInfo)
	case 0:
		response.FailWithMessage("注册审核中，暂不能登录", c)
	case 2:
		response.FailWithMessage("注册申请被驳回，暂不能登录", c)
	default:
		response.FailWithMessage("注册状态异常，暂不能登录", c)
	}
}

// RetrievePassword 找回密码
// @Tags HealthManager
// @Summary 找回密码
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body manager.FdHealthManager true "找回密码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"登录成功"}"
// @Router /healthManager/retrievePassword [post]
func (healthManagerApi *HealthManagerApi) RetrievePassword(c *gin.Context) {
	var mr managerReq.RetrievePasswordRequest
	err := c.ShouldBindJSON(&mr)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(mr, utils.CodeLoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if smsErr := sms.CheckSMSCode(mr.Phone, mr.Code); smsErr != nil {
		response.FailWithMessage("验证码有误,请核实!", c)
		return
	}
	managerInfo, UpdateErr := HealthManagerService.UpdateManagerByWhere(map[string]interface{}{"phone": mr.Phone}, map[string]interface{}{"password": utils.BcryptHash(mr.Password)})
	if UpdateErr != nil {
		response.FailWithMessage("设置新密码失败", c)
		return
	}
	healthManagerApi.TokenNextB1(c, *managerInfo)
}

// TokenNextB1 C端登入以后签发jwt
func (healthManagerApi *HealthManagerApi) TokenNextB1(c *gin.Context, healthManager manager.HealthManager) {
	token, claims, err := utils.LoginTokenB1(&healthManager)
	if err != nil {
		global.GVA_LOG.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	if global.GVA_CONFIG.System.UseMultipoint {
		if err := utils.SetRedisJWT(token, "B1:SignInToken:"+strconv.FormatUint(uint64(healthManager.HmID), 10)); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(gin.H{
			"token":   token,
			"manager": healthManager,
		}, "登录成功", c)
		return
	}
	if jwtStr, err := jwtService.GetRedisJWT("B1:SignInToken:" + strconv.FormatUint(uint64(healthManager.HmID), 10)); errors.Is(err, redis.Nil) {
		if err := utils.SetRedisJWT(token, "B1:SignInToken:"+strconv.FormatUint(uint64(healthManager.HmID), 10)); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(gin.H{
			"token":   token,
			"manager": healthManager,
		}, "登录成功", c)
	} else if err != nil {
		global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT system.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := jwtService.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := utils.SetRedisJWT(token, "B1:SignInToken:"+strconv.FormatUint(uint64(healthManager.HmID), 10)); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(gin.H{
			"token":   token,
			"manager": healthManager,
		}, "登录成功", c)
	}
}

// GetManagerInfo 获取健管师信息
// @Tags      HealthManager
// @Summary   获取健管师信息
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Success   200  {object}  response.Response{data=managerRes.ManagerInfoResponse,msg=string}  "获取成功"
// @Router    /manager/getManagerInfo [GET]
func (healthManagerApi *HealthManagerApi) GetManagerInfo(c *gin.Context) {
	hmID := utils.GetHmID(c)
	if hmID == 0 {
		response.FailWithMessage("未获取到登录信息", c)
		return
	}
	info, err := HealthManagerService.GetHealthManagerInfo(hmID)
	if err != nil {
		global.GVA_LOG.Error("获取健管师详情失败", zap.Error(err))
		response.FailWithMessage("获取健管师详情失败", c)
		return
	}
	var certImages []string
	if len(info.CertificationImages) > 0 {
		_ = json.Unmarshal(info.CertificationImages, &certImages)
	}
	resp := managerRes.ManagerInfoResponse{
		HmID:                info.HmID,
		CertificationNo:     info.CertificationNo,
		Avatar:              info.Avatar,
		Grade:               info.Grade,
		Type:                info.Type,
		Name:                info.Name,
		Phone:               info.Phone,
		ServiceCenterName:   info.ServiceStation.CreatorInfo.Name,
		ServiceStationName:  info.ServiceStation.Name,
		Sex:                 info.Sex,
		IDNumber:            info.IDNumber,
		CertificationImages: certImages,
	}
	response.OkWithDetailed(resp, "获取成功", c)
}

// UpdateManager 修改健管师信息
// @Tags      HealthManager
// @Summary   修改健管师信息
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Param     data  body      managerReq.UpdateManagerRequest  true  "修改健管师信息"
// @Success   200   {object}  response.Response{msg=string}    "更新成功"
// @Router    /manager/updateManager [put]
func (healthManagerApi *HealthManagerApi) UpdateManager(c *gin.Context) {
	var req managerReq.UpdateManagerRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	hmID := utils.GetHmID(c)
	if hmID == 0 {
		response.FailWithMessage("未获取到登录信息", c)
		return
	}
	verify := utils.Rules{
		"Name":  {utils.NotEmpty()},
		"Phone": {utils.NotEmpty()},
	}
	if err := utils.Verify(req, verify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	_, err := HealthManagerService.UpdateManagerByID(hmID, req)
	if err != nil {
		global.GVA_LOG.Error("更新健管师信息失败", zap.Error(err))
		response.FailWithMessage("更新失败", c)
		return
	}
	response.OkWithMessage("更新成功", c)
}

// ChangePassword 修改密码
// @Tags      HealthManager
// @Summary   修改密码
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Param     data  body      managerReq.ChangePasswordRequest  true  "修改密码"
// @Success   200   {object}  response.Response{msg=string}     "修改成功"
// @Router    /manager/changePassword [post]
func (healthManagerApi *HealthManagerApi) ChangePassword(c *gin.Context) {
	var req managerReq.ChangePasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	verify := utils.Rules{
		"Phone":              {utils.NotEmpty()},
		"OldPassword":        {utils.NotEmpty()},
		"NewPassword":        {utils.NotEmpty()},
		"ConfirmNewPassword": {utils.NotEmpty()},
	}
	if err := utils.Verify(req, verify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if req.NewPassword != req.ConfirmNewPassword {
		response.FailWithMessage("新密码与确认密码不一致", c)
		return
	}
	hmID := utils.GetHmID(c)
	if hmID == 0 {
		response.FailWithMessage("未获取到登录信息", c)
		return
	}
	if err := HealthManagerService.ChangePassword(req.Phone, hmID, req.OldPassword, req.NewPassword); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("修改成功", c)
}

// GetMyManager 获取健管师列表
// @Tags      HealthManager
// @Summary   获取健管师列表
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Param     data  body      managerReq.ChangePasswordRequest  true  "获取健管师列表"
// @Success   200   {object}  response.Response{msg=string}     "获取成功"
// @Router    /manager/getMyManager [get]
func (healthManagerApi *HealthManagerApi) GetMyManager(c *gin.Context) {
	phone := c.Query("phone")
	userID := utils.GetUserID(c)
	var hm *manager.HealthManager
	u, _ := UserService.GetUserData(userID)
	var bound bool
	if phone != "" {
		managerInfo, err := HealthManagerService.FindManagerByWhere(map[string]interface{}{"phone": phone}, "*")
		if errors.Is(err, gorm.ErrRecordNotFound) {
			response.FailWithMessage("未查询到该手机号的健管师", c)
			return
		}
		// 进一步加载服务站与中心信息
		full, hErr := HealthManagerService.GetHealthManagerInfo(managerInfo.HmID)
		if hErr == nil {
			hm = &full
		} else {
			hm = managerInfo
		}
		bound = u.HealthManagerID == managerInfo.HmID
	} else {
		bound = u.HealthManagerID != 0
		if u.HealthManagerID != 0 {
			info, hErr := HealthManagerService.GetHealthManagerInfo(u.HealthManagerID)
			if hErr != nil {
				response.FailWithMessage("获取健管师信息失败", c)
				return
			}
			hm = &info
		}
	}
	var serviceStationName string
	var serviceCenterName string
	var resp managerRes.GetMyManagerResponse
	if hm != nil {
		resp.HmID = hm.HmID
		resp.Avatar = hm.Avatar
		resp.Grade = hm.Grade
		resp.Phone = hm.Phone
		if hm.ServiceStation != nil {
			serviceStationName = hm.ServiceStation.Name
			if hm.ServiceStation.CreatorInfo.Name != "" {
				serviceCenterName = hm.ServiceStation.CreatorInfo.Name
			}
		}
	}
	resp.ServiceStationName = serviceStationName
	resp.ServiceCenterName = serviceCenterName
	resp.Bound = bound
	response.OkWithData(resp, c)
}
